#include "RouteService.h"
#include <QNetworkRequest>
#include <QUrl>
#include <QUrlQuery>
#include <QDebug>
#include <QtMath>

RouteService::RouteService(QObject *parent)
    : QObject(parent)
    , m_networkManager(new QNetworkAccessManager(this))
    , m_currentReply(nullptr)
    , m_provider("direct")
    , m_apiKey("")
    , m_isPlanning(false)
    , m_currentProvider(DirectLine)
{
    qDebug() << "RouteService: 初始化";
}

RouteService::~RouteService()
{
    cancelRequest();
}

void RouteService::setProvider(const QString &provider)
{
    if (m_provider != provider) {
        m_provider = provider;
        
        // 更新当前提供商枚举
        if (provider == "direct") {
            m_currentProvider = DirectLine;
        } else if (provider == "openroute") {
            m_currentProvider = OpenRouteService;
        } else if (provider == "google") {
            m_currentProvider = GoogleDirections;
        } else if (provider == "bing") {
            m_currentProvider = BingMaps;
        }
        
        emit providerChanged();
        qDebug() << "RouteService: 切换路线服务提供商 ->" << provider;
    }
}

void RouteService::setApiKey(const QString &apiKey)
{
    if (m_apiKey != apiKey) {
        m_apiKey = apiKey;
        emit apiKeyChanged();
        qDebug() << "RouteService: 设置API密钥";
    }
}

void RouteService::requestRoute(const QVariantList &waypoints)
{
    if (waypoints.isEmpty()) {
        emit routeError("路径点列表为空");
        return;
    }
    
    if (waypoints.size() < 2) {
        emit routeError("至少需要2个路径点");
        return;
    }
    
    // 取消之前的请求
    cancelRequest();
    
    m_isPlanning = true;
    emit isPlanningChanged();
    emit routeProgress(0);
    
    m_currentWaypoints = waypoints;
    
    qDebug() << "RouteService: 请求路线规划，路径点数:" << waypoints.size() << "提供商:" << m_provider;
    
    // 根据提供商选择规划方法
    switch (m_currentProvider) {
        case DirectLine:
            planDirectLine(waypoints);
            break;
        case OpenRouteService:
            planOpenRouteService(waypoints);
            break;
        case GoogleDirections:
            planGoogleDirections(waypoints);
            break;
        case BingMaps:
            planBingMaps(waypoints);
            break;
        default:
            planDirectLine(waypoints);
            break;
    }
}

void RouteService::setRouteProvider(const QString &provider)
{
    setProvider(provider);
}

void RouteService::clearRoute()
{
    cancelRequest();
    m_currentWaypoints.clear();
    qDebug() << "RouteService: 清除路线";
}

void RouteService::cancelRequest()
{
    if (m_currentReply) {
        m_currentReply->abort();
        m_currentReply->deleteLater();
        m_currentReply = nullptr;
    }
    
    if (m_isPlanning) {
        m_isPlanning = false;
        emit isPlanningChanged();
    }
}

// ==================== 路线规划实现 ====================

void RouteService::planDirectLine(const QVariantList &waypoints)
{
    qDebug() << "RouteService: 使用直线规划模式";
    
    emit routeProgress(20);
    
    QVariantList path;
    double totalDistance = 0;
    
    // 遍历所有路径点，生成插值点
    for (int i = 0; i < waypoints.size(); i++) {
        QVariantMap point = waypoints[i].toMap();
        double lon = point["lon"].toDouble();
        double lat = point["lat"].toDouble();
        
        // 添加当前路径点
        QVariantMap pathPoint;
        pathPoint["lon"] = lon;
        pathPoint["lat"] = lat;
        path.append(pathPoint);
        
        // 如果不是最后一个点，在两点之间插值
        if (i < waypoints.size() - 1) {
            QVariantMap nextPoint = waypoints[i + 1].toMap();
            double nextLon = nextPoint["lon"].toDouble();
            double nextLat = nextPoint["lat"].toDouble();
            
            // 计算距离
            double segmentDistance = calculateDistance(lon, lat, nextLon, nextLat);
            totalDistance += segmentDistance;
            
            // 根据距离决定插值点数量（每50米一个点）
            int segments = qMax(1, static_cast<int>(segmentDistance / 50.0));
            
            // 生成插值点
            QVariantList interpolated = interpolatePoints(lon, lat, nextLon, nextLat, segments);
            for (const QVariant &interpPoint : interpolated) {
                path.append(interpPoint);
            }
        }
    }
    
    emit routeProgress(100);
    
    // 估算行驶时长（假设平均速度5 km/h）
    double duration = totalDistance / (5000.0 / 3600.0);
    
    m_isPlanning = false;
    emit isPlanningChanged();
    
    emit routeReady(path, totalDistance, duration);
    qDebug() << "RouteService: 直线规划完成，路径点数:" << path.size() << "总距离:" << totalDistance << "米";
}

void RouteService::planOpenRouteService(const QVariantList &waypoints)
{
    if (m_apiKey.isEmpty()) {
        emit routeError("OpenRouteService需要API密钥，请先设置apiKey");
        m_isPlanning = false;
        emit isPlanningChanged();
        return;
    }
    
    emit routeProgress(10);
    
    // 构建请求URL
    QString baseUrl = "https://api.openrouteservice.org/v2/directions/driving-car/geojson";
    
    // 构建坐标列表
    QJsonArray coordinates;
    for (const QVariant &wp : waypoints) {
        QVariantMap point = wp.toMap();
        QJsonArray coord;
        coord.append(point["lon"].toDouble());
        coord.append(point["lat"].toDouble());
        coordinates.append(coord);
    }
    
    // 构建POST请求体
    QJsonObject requestBody;
    requestBody["coordinates"] = coordinates;
    
    QJsonDocument doc(requestBody);
    QByteArray data = doc.toJson();
    
    // 创建网络请求
    QNetworkRequest request;
    request.setUrl(QUrl(baseUrl));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    request.setRawHeader("Authorization", m_apiKey.toUtf8());
    
    emit routeProgress(30);
    
    // 发送POST请求
    m_currentReply = m_networkManager->post(request, data);
    connect(m_currentReply, &QNetworkReply::finished, this, &RouteService::onNetworkReplyFinished);
    // Qt 5.12中使用error信号而不是errorOccurred
    connect(m_currentReply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
            this, &RouteService::onNetworkError);
    
    qDebug() << "RouteService: 发送OpenRouteService请求";
}

void RouteService::planGoogleDirections(const QVariantList &waypoints)
{
    if (m_apiKey.isEmpty()) {
        emit routeError("Google Directions需要API密钥，请先设置apiKey");
        m_isPlanning = false;
        emit isPlanningChanged();
        return;
    }
    
    emit routeProgress(10);
    
    // 构建请求URL
    QString baseUrl = "https://maps.googleapis.com/maps/api/directions/json";
    
    // 起点和终点
    QVariantMap origin = waypoints.first().toMap();
    QVariantMap destination = waypoints.last().toMap();
    
    QString originStr = QString::number(origin["lat"].toDouble(), 'f', 6) + "," +
                        QString::number(origin["lon"].toDouble(), 'f', 6);
    QString destStr = QString::number(destination["lat"].toDouble(), 'f', 6) + "," +
                      QString::number(destination["lon"].toDouble(), 'f', 6);
    
    // 构建URL参数
    QUrlQuery query;
    query.addQueryItem("origin", originStr);
    query.addQueryItem("destination", destStr);
    query.addQueryItem("key", m_apiKey);
    
    // 如果有中间点，添加waypoints参数
    if (waypoints.size() > 2) {
        QStringList waypointsList;
        for (int i = 1; i < waypoints.size() - 1; i++) {
            QVariantMap wp = waypoints[i].toMap();
            QString wpStr = QString::number(wp["lat"].toDouble(), 'f', 6) + "," +
                           QString::number(wp["lon"].toDouble(), 'f', 6);
            waypointsList.append(wpStr);
        }
        query.addQueryItem("waypoints", waypointsList.join("|"));
    }
    
    QUrl url(baseUrl);
    url.setQuery(query);
    
    emit routeProgress(30);
    
    // 创建网络请求
    QNetworkRequest request(url);
    m_currentReply = m_networkManager->get(request);
    connect(m_currentReply, &QNetworkReply::finished, this, &RouteService::onNetworkReplyFinished);
    // Qt 5.12中使用error信号而不是errorOccurred
    connect(m_currentReply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
            this, &RouteService::onNetworkError);
    
    qDebug() << "RouteService: 发送Google Directions请求";
}

void RouteService::planBingMaps(const QVariantList &waypoints)
{
    if (m_apiKey.isEmpty()) {
        emit routeError("Bing Maps需要API密钥，请先设置apiKey");
        m_isPlanning = false;
        emit isPlanningChanged();
        return;
    }
    
    emit routeProgress(10);
    
    // 构建请求URL
    QString baseUrl = "https://dev.virtualearth.net/REST/v1/Routes";
    
    // 构建路径点参数
    QStringList waypointParams;
    for (int i = 0; i < waypoints.size(); i++) {
        QVariantMap wp = waypoints[i].toMap();
        QString wpStr = QString("wp.%1=%2,%3")
                        .arg(i)
                        .arg(wp["lat"].toDouble(), 0, 'f', 6)
                        .arg(wp["lon"].toDouble(), 0, 'f', 6);
        waypointParams.append(wpStr);
    }
    
    QString url = baseUrl + "?" + waypointParams.join("&") + "&key=" + m_apiKey;
    
    emit routeProgress(30);
    
    // 创建网络请求
    QUrl requestUrl(url);
    QNetworkRequest request(requestUrl);
    m_currentReply = m_networkManager->get(request);
    connect(m_currentReply, &QNetworkReply::finished, this, &RouteService::onNetworkReplyFinished);
    // Qt 5.12中使用error信号而不是errorOccurred
    connect(m_currentReply, static_cast<void(QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
            this, &RouteService::onNetworkError);
    
    qDebug() << "RouteService: 发送Bing Maps请求";
}

// ==================== 网络响应处理 ====================

void RouteService::onNetworkReplyFinished()
{
    if (!m_currentReply) {
        return;
    }
    
    emit routeProgress(80);
    
    QByteArray data = m_currentReply->readAll();
    
    if (m_currentReply->error() == QNetworkReply::NoError) {
        qDebug() << "RouteService: 收到网络响应，大小:" << data.size();
        
        // 根据提供商解析响应
        switch (m_currentProvider) {
            case OpenRouteService:
                parseOpenRouteServiceResponse(data);
                break;
            case GoogleDirections:
                parseGoogleDirectionsResponse(data);
                break;
            case BingMaps:
                parseBingMapsResponse(data);
                break;
            default:
                emit routeError("未知的路线服务提供商");
                break;
        }
    } else {
        emit routeError("网络请求失败: " + m_currentReply->errorString());
    }
    
    m_currentReply->deleteLater();
    m_currentReply = nullptr;
    
    m_isPlanning = false;
    emit isPlanningChanged();
}

void RouteService::onNetworkError(QNetworkReply::NetworkError error)
{
    qWarning() << "RouteService: 网络错误:" << error;
    emit routeError("网络错误: " + QString::number(error));
    
    m_isPlanning = false;
    emit isPlanningChanged();
}

// ==================== 响应解析 ====================

void RouteService::parseOpenRouteServiceResponse(const QByteArray &data)
{
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull() || !doc.isObject()) {
        emit routeError("OpenRouteService响应解析失败");
        return;
    }
    
    QJsonObject root = doc.object();
    QJsonArray features = root["features"].toArray();
    
    if (features.isEmpty()) {
        emit routeError("OpenRouteService未返回路线数据");
        return;
    }
    
    QJsonObject feature = features[0].toObject();
    QJsonObject geometry = feature["geometry"].toObject();
    QJsonArray coordinates = geometry["coordinates"].toArray();
    
    // 提取路线坐标
    QVariantList path;
    for (const QJsonValue &coord : coordinates) {
        QJsonArray point = coord.toArray();
        QVariantMap pathPoint;
        pathPoint["lon"] = point[0].toDouble();
        pathPoint["lat"] = point[1].toDouble();
        path.append(pathPoint);
    }
    
    // 提取距离和时长
    QJsonObject properties = feature["properties"].toObject();
    QJsonObject summary = properties["summary"].toObject();
    double distance = summary["distance"].toDouble();
    double duration = summary["duration"].toDouble();
    
    emit routeProgress(100);
    emit routeReady(path, distance, duration);
    qDebug() << "RouteService: OpenRouteService路线规划完成，路径点数:" << path.size();
}

void RouteService::parseGoogleDirectionsResponse(const QByteArray &data)
{
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull() || !doc.isObject()) {
        emit routeError("Google Directions响应解析失败");
        return;
    }
    
    QJsonObject root = doc.object();
    QString status = root["status"].toString();
    
    if (status != "OK") {
        emit routeError("Google Directions错误: " + status);
        return;
    }
    
    QJsonArray routes = root["routes"].toArray();
    if (routes.isEmpty()) {
        emit routeError("Google Directions未返回路线数据");
        return;
    }
    
    QJsonObject route = routes[0].toObject();
    QJsonObject overviewPolyline = route["overview_polyline"].toObject();
    QString encodedPolyline = overviewPolyline["points"].toString();
    
    // 解码polyline
    QVariantList path = decodePolyline(encodedPolyline);
    
    // 提取距离和时长
    QJsonArray legs = route["legs"].toArray();
    double totalDistance = 0;
    double totalDuration = 0;
    
    for (const QJsonValue &leg : legs) {
        QJsonObject legObj = leg.toObject();
        totalDistance += legObj["distance"].toObject()["value"].toDouble();
        totalDuration += legObj["duration"].toObject()["value"].toDouble();
    }
    
    emit routeProgress(100);
    emit routeReady(path, totalDistance, totalDuration);
    qDebug() << "RouteService: Google Directions路线规划完成，路径点数:" << path.size();
}

void RouteService::parseBingMapsResponse(const QByteArray &data)
{
    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull() || !doc.isObject()) {
        emit routeError("Bing Maps响应解析失败");
        return;
    }
    
    QJsonObject root = doc.object();
    QJsonArray resourceSets = root["resourceSets"].toArray();
    
    if (resourceSets.isEmpty()) {
        emit routeError("Bing Maps未返回路线数据");
        return;
    }
    
    QJsonObject resourceSet = resourceSets[0].toObject();
    QJsonArray resources = resourceSet["resources"].toArray();
    
    if (resources.isEmpty()) {
        emit routeError("Bing Maps资源为空");
        return;
    }
    
    QJsonObject resource = resources[0].toObject();
    QJsonArray routeLegs = resource["routeLegs"].toArray();
    
    // 提取路线坐标
    QVariantList path;
    double totalDistance = 0;
    double totalDuration = 0;
    
    for (const QJsonValue &leg : routeLegs) {
        QJsonObject legObj = leg.toObject();
        QJsonArray itineraryItems = legObj["itineraryItems"].toArray();
        
        for (const QJsonValue &item : itineraryItems) {
            QJsonObject itemObj = item.toObject();
            QJsonObject maneuverPoint = itemObj["maneuverPoint"].toObject();
            QJsonArray coordinates = maneuverPoint["coordinates"].toArray();
            
            QVariantMap pathPoint;
            pathPoint["lat"] = coordinates[0].toDouble();
            pathPoint["lon"] = coordinates[1].toDouble();
            path.append(pathPoint);
        }
        
        totalDistance += legObj["travelDistance"].toDouble() * 1000; // 转换为米
        totalDuration += legObj["travelDuration"].toDouble();
    }
    
    emit routeProgress(100);
    emit routeReady(path, totalDistance, totalDuration);
    qDebug() << "RouteService: Bing Maps路线规划完成，路径点数:" << path.size();
}

// ==================== 工具函数 ====================

double RouteService::calculateDistance(double lon1, double lat1, double lon2, double lat2)
{
    // Haversine公式计算地球表面两点间距离
    const double R = 6371000; // 地球半径（米）
    
    double dLat = qDegreesToRadians(lat2 - lat1);
    double dLon = qDegreesToRadians(lon2 - lon1);
    
    double a = qSin(dLat / 2) * qSin(dLat / 2) +
               qCos(qDegreesToRadians(lat1)) * qCos(qDegreesToRadians(lat2)) *
               qSin(dLon / 2) * qSin(dLon / 2);
    
    double c = 2 * qAtan2(qSqrt(a), qSqrt(1 - a));
    
    return R * c;
}

QVariantList RouteService::interpolatePoints(double lon1, double lat1, double lon2, double lat2, int segments)
{
    QVariantList result;
    
    for (int i = 1; i < segments; i++) {
        double t = static_cast<double>(i) / segments;
        
        QVariantMap point;
        point["lon"] = lon1 + (lon2 - lon1) * t;
        point["lat"] = lat1 + (lat2 - lat1) * t;
        result.append(point);
    }
    
    return result;
}

QVariantList RouteService::decodePolyline(const QString &encoded)
{
    QVariantList result;
    int index = 0;
    int lat = 0;
    int lng = 0;
    
    while (index < encoded.length()) {
        int b, shift = 0, resultVal = 0;
        
        do {
            b = encoded.at(index++).toLatin1() - 63;
            resultVal |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        
        int dlat = ((resultVal & 1) ? ~(resultVal >> 1) : (resultVal >> 1));
        lat += dlat;
        
        shift = 0;
        resultVal = 0;
        
        do {
            b = encoded.at(index++).toLatin1() - 63;
            resultVal |= (b & 0x1f) << shift;
            shift += 5;
        } while (b >= 0x20);
        
        int dlng = ((resultVal & 1) ? ~(resultVal >> 1) : (resultVal >> 1));
        lng += dlng;
        
        QVariantMap point;
        point["lat"] = lat / 1E5;
        point["lon"] = lng / 1E5;
        result.append(point);
    }
    
    return result;
}
